home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
UTILITY
/
FSULTRA1.ARJ
/
ULTRAMAC.C
< prev
next >
Wrap
Text File
|
1992-06-18
|
7KB
|
208 lines
/*
FSU - ULTRA The greatest random number generator that ever was
or ever will be. Way beyond Super-Duper.
(Just kidding, but we think its a good one.)
Authors: Arif Zaman (arif@stat.fsu.edu) and
George Marsaglia (geo@stat.fsu.edu).
Date: 27 May 1992
Version: 1.05
Copyright: To obtain permission to incorporate this program into
any commercial product, please contact the authors at
the e-mail address given above or at
Department of Statistics and
Supercomputer Computations Research Institute
Florida State University
Tallahassee, FL 32306.
See Also: README for a brief description
ULTRA.DOC for a detailed description
-----------------------------------------------------------------------
*/
/*
File: ULTRA.C
This is the ULTRA random number generator written entirely in C.
This may serve as a model for an assembler version of this routine.
The programmer should avoid simply duplicating and instead use the
usual assembler features to increase the speed of this routine.
Especially the subroutine SWB should be replaced by the one
machine instruction (usually called subtract-with-borrow) that
is available in almost every hardware.
For people not familiar with 8086 assembler, it may help to
consult this when reading the assembler code. This program should
be a dropin replacement for the assembler versions, but is about
half as fast.
*/
#define N 37 /* size of table */
#define N2 24 /* The shorter lag */
long swb32[N], /* These arrays contian the seed mixed with */
swb16[N], /* a congruential. They are used 32, 16, and 8 */
swb8[N], /* bits at a time respectively. */
swbseed[N] = { 0x0D45D69A, /* The seed for the SWB generator */
0x9DB73B1A, 0xA84604E8, 0x7C5F0CA5, 0xBC0196CE, 0xFF4CB42E, 0x7ACA6BE3,
0xA9ED2A5A, 0x6405A8F7, 0xAC00D4F8, 0xBDD1FC77, 0x064F9DC5, 0xF10AB737,
0x781293D3, 0x8410C2D2, 0x1C6587DB, 0x7D8F8F0F, 0xF3DCC4EA, 0xB965F99F,
0x9A0094D1, 0x65976D1C, 0x09173DC1, 0x8E38B992, 0x84701D44, 0x14F0E1B9,
0xE8A1EC5F, 0x1E925A12, 0xE77A0B5B, 0xCDB5926E, 0xD16260C8, 0xC917E806,
0x519076AA, 0x7BF6C21C, 0x808C0C90, 0x3E93C7B8, 0x707D6EA0, 0xF1DB698D};
char flags=0; /* The carry flag for the SWB generator */
long unsigned congx = 0x1C3a128F; /* Seed for congruential generator */
long *swb32p; short swb32n=0; /* A counter and a */
short *swb16p; short swb16n=0; /* pointer is kept for */
char *swb8p; short swb8n=0; /* each array. */
char swb1[32]; /* The swb1 is slightly */
char *swb1p; short swb1n=0; /* different. */
/*************************************************************************
* For each of swb32, swb16, swb8 and swb1, there is an array, a counter *
* and a pointer. The counters count down, the pointers go up. When the *
* counter reaches zero, a fill routine is called to refill the array. *
************************************************************************/
/* rinit initializes the constants and fills the seed array one bit at
a time by taking the leading bit of the xor of a shift register
and a congruential sequence. The same congruential generator continues
to be used as a mixing generator for the Subtract-with-borrow generator
to produce the `ultra' random numbers
Since this is called just once, speed doesn't matter much and it might
be fine to leave this subroutine coded just as it is.
PS: there are quick and easy ways to fill this, but since random number
generators are really "randomness amplifiers", it is important to
start off on the right foot. This is why we take such care here.
*/
void rinit(long unsigned congy,long unsigned shrgx)
{ short i,j;
unsigned long tidbits;
congx=congy*2+1;
for (i=0;i<N;i++)
{ for (j=32;j>0;j--)
{ congx = congx * 69069;
shrgx = shrgx ^ (shrgx >> 15);
shrgx = shrgx ^ (shrgx << 17);
tidbits = (tidbits>>1) | (0x80000000 & (congx^shrgx));
}
swbseed[i] = tidbits;
}
swb32n = swb16n = swb8n = swb1n = 0;
flags = 0;
}
/* SWB is the subtract-with-borrow operation which should be one line
in assembler code. This should be done by using the hardware s-w-b
operation in the SWBfill routine.
What has been done here is to look at the msb of x, y and z=x-y-c.
Using these three bits, one can determine if a borrow bit is needed
or not according to the following table:
msbz=0 msby=0 msby=1 msbz=1 msby=0 msby=1
msbx=0 0 1 msbx=0 1 1
msbx=1 0 0 msbx=1 0 1
PS: note that the definition is very carefully written because the
calls to SWB have y and z as the same memory location, so y must
be tested before z is assigned a value.
*/
#define SWB(c,x,y,z) \
c = (y<0) ? (((z=x-y-c) < 0) || (x>=0)) : (((z=x-y-c) < 0) && (x>=0));
void SWBfill(long *x)
{ short i;
/*
The following two lines are the heart of the system and should be
written is assembler to be as fast as possible. It may even make sense
to unravel the loop and simply wirte 37 consecutive SWB operations!
*/
for (i=0; i<N2; i++) SWB(flags,swbseed[i+N-N2],swbseed[i],swbseed[i]);
for (i=N2; i<N; i++) SWB(flags,swbseed[i -N2],swbseed[i],swbseed[i]);
#ifndef fast
for (i=0; i<N; i++) *(x++) = swbseed[i] ^ (congx = congx * 69069);
#else
for (i=0; i<N; i++) *(x++) = swbseed[i];
#endif
}
long swb32fill(void)
{ swb32p = &swb32[0];
SWBfill(&swb32[0]);
swb32n = N-1;
return *(swb32p++);
}
short swb16fill(void)
{ swb16p = (short *) &swb16[0];
SWBfill((long *) swb16p);
swb16n = 2*N-1;
return *(swb16p++);
}
char swb8fill(void)
{ swb8p = (char *) &swb8[0];
SWBfill((long *) swb8p);
swb8n = 4*N-1;
return *(swb8p++);
}
#define i32bit() ((swb32n--) ? *(swb32p++) : swb32fill())
#define i31bit() (((swb32n--) ? *(swb32p++) : swb32fill()) & 0x7FFFFFFF)
#define i16bit() ((swb16n--) ? *(swb16p++) : swb16fill())
#define i15bit() (((swb16n--) ? *(swb16p++) : swb16fill()) & 0x7FFF)
#define i8bit() ((swb8n--) ? *(swb8p++) : swb8fill() )
#define i7bit() (((swb8n--) ? *(swb8p++) : swb8fill() ) & 0x7F)
char swb1fill(void)
{ unsigned long i,j;
swb1p = &swb1[0];
swb1n = 31;
i = i32bit();
for (j=0;j<32;j++) { swb1[j] = i&1; i=i>>1; }
return *(swb1p++);
}
#define i1bit() ((swb1n--) ? *(swb1p++) : swb1fill() )
#define two2neg31 ( (2.0/0x10000) / 0x10000 )
#define two2neg32 ( (1.0/0x10000) / 0x10000 )
float vni(void)
{ long temp;
temp = i32bit();
if (temp & 0xFF000000) { return temp * two2neg31; }
return (temp + i32bit() * two2neg32) * two2neg31;
}
float uni(void)
{ long temp;
temp = i31bit();
if (temp & 0xFF000000) { return temp * two2neg31; }
return (temp + i32bit() * two2neg32) * two2neg31;
}
double dvni(void)
{ unsigned long temp;
temp = i32bit();
return ( (long) i32bit() + temp * two2neg32) * two2neg31; }
double duni(void)
{ unsigned long temp;
temp = i32bit();
return ( i31bit() + temp * two2neg32) * two2neg31; }